<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
<canvas id="canvas" width="800" height="600"></canvas>
<script>
	// 首先，我们要在空白的html页面上添加一个canvas标签
	// 下面，我们来实现javscript部分的工作。首先是定义辅助构造器point，最简单的实现方法如下
	function Point(x, y) {
		this.x = x;
		this.y = y;
	}

	// 接下来，轮到构造器Line了，他会根据勾股定理计算出给定两点之间的距离
	function Line(p1, p2) {
		this.p1 = p1;
		this.p2 = p2;
		this.length = Math.sqrt(
			Math.pow(p1.x - p2.x, 2) +
			Math.pow(p1.y - p2.y, 2)
		);
	}

	// 下一步，我们就可以进入shape构造器的定义了。该构造器需要有一个自己的potnts属性（以及链接这些point的Lines属性）。另外我们还需要一个初始化方法init()，用于定义其原型
	function Shape() {
		this.points = [];
		this.lines = [];
		this.init();
	}

	// 接下来进入正题：定义Shape.Prototype的方法
	Shape.prototype = {
		constructor: Shape,
		init: function() {
			if(this.context == undefined) {
				var canvas = document.getElementById('canvas');
				Shape.prototype.context = canvas.getContext('2d');
			}
		},
		draw: function() {
			var i, ctx = this.context;
			ctx.strokeStyle = this.getColor();
			ctx.beginPath();
			ctx.moveTo(this.points[0].x, this.points[0].y);
			for(i = 1;i < this.points.length;i++){
				ctx.lineTo(this.points[i].x, this.points[i].y);
			}
			ctx.closePath();
			ctx.stroke();
		},
		getColor: function() {
			var i, rgb = [];
			for(i = 0;i < 3;i++) {
				rgb[i] = Math.round(255 * Math.random());
			}
			return 'rgb(' + rgb.join(',') + ')';
		},
		getLines: function() {
			if(this.lines.length > 0){
				return this.lines;
			}
			var i,lines = [];
			for(i = 0;i < this.points.length;i++){
				lines[i] = new Line(this.points[i],
				this.points[i + 1] || this.points[0]);
			}
			this.lines = lines;
			return lines;
		},
		getArea: function() {},
		getPerimeter: function() {
			var i,perim = 0,lines = this.getLines();
			for(i = 0;i < lines.length;i++){
				perim += lines[i].length;
			}
			return perim;
		}
	};

	// 接着是子对象构造器，先从Triangle开始
	function Triangle(a, b, c){
		this.points = [a, b, c];
		this.getArea = function() {
			var p = this.getPerimeter();
			s = p / 2;
			return Math.sqrt(
				s 
				* (s - this.lines[0].length)
				* (s - this.lines[1].length)
				* (s - this.lines[2].length)
			);
		};
	}

	// 在Triangle构造器中，我们会将其接收到的三个point对象赋值给this.points。然后再利用海伦公式实现其getArea()方法，公式如下
	// Area = s(s - a)(s - b)(s - c);
	// 其中，s为半周长（就是周长除以2）
	// 接下来轮到Rectangle构造器了，该对象所接受的参数是一个point对象（即左上角位置）和两边的长度。然后再以该point起点，自行填充其points数组。
	function Rectangle(p, side_a, side_b) {
		this.points = [
			p,
			new Point(p.x + side_a, p.y),
			new Point(p.x + side_a, p.y + side_b),
			new Point(p.x, p.y + side_b)
		];
		this.getArea = function() {
			return side_a * side_b;
		}
	}

	// 最后一个子对象构造器是Square。由于Square是Rectangle的一种特例，所以对于它的实现，我们可以重用Rectangle，而其中最简单的莫过于构造器借用法了
	function Square(p, side) {
		Rectangle.call(this, p, side, side);
	}

	// 到这里，所有的构造器的实现都已经完成了，让我们开始处理他们的继承关系，几乎所有的仿传统模式都符合我们的需求。下面，让我们来试着将其修改为原型链模式，并提供一个父对象实体，然后直接将其设置为子对象的原型。这样一来，我们就没有必须要为每一个子对象的原型创建新的实体了 - 因为他们可以通过原型实现完全共享
	(function() {
		var s = new Shape();
		Triangle.prototype = s;
		Rectangle.prototype = s;
		Square.prototype = s;
	})();

	// 接下来，我们来绘制一个图形，测试一下代码。首先来定义一个Triangle对象的三个point:
	var p1 = new Point(100, 100);
	var p2 = new Point(300, 100);
	var p3 = new Point(200, 0);

	// 然后，将这三个point传递给Triangle构造器，以创建一个Triangle实例：
	var t = new Triangle(p1, p2, p3);

	// 接着，我们就可以调用相关的方法在画布上会出三角形，并计算出他的面积和周长
	t.draw();
	console.log(t.getPerimeter());
	console.log(t.getArea());

	// 然后是Rectangle的实例化
	var r = new Rectangle(new Point(200, 200), 50, 100);
	r.draw();
	console.log(r.getArea());
	console.log(r.getPerimeter());

	// 最后是Square
	var s = new Square(new Point(130, 130), 50);
	s.draw();
	console.log(s.getArea());
	console.log(s.getPerimeter());

	// 如果想给这些图形绘制增加一些乐趣，我们也可以像下面这样，在绘制Square的时候重用triangle的point
	new Square(p1, 200).draw();
</script>
</body>
</html>